/*******************************************
 * Copyright 2007 Aphrodite Framework for javaME .
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v2.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * Email : owner@aphroditeme.dev.java.net
 * Contributors:
 *     Kent Elton - initial API and implementation
 *******************************************/
package com.aphrodite.ui.widgets.browser;

import java.io.IOException;
import java.io.InputStream;
import java.util.Vector;

import javax.microedition.io.HttpConnection;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Graphics;

import com.aphrodite.io.CommProcessNotifier;
import com.aphrodite.io.HttpCommManager;
import com.aphrodite.ui.widgets.Theme;
import com.aphrodite.xml.XMLReader;

//must implement traverse
/**
 * Browser widget
 * <p>
 * Colors should be specified in hex<br/> <img
 * src="../../../resources/browser.png">
 * </p>
 * 
 * @author kentelt
 * 
 */
public class HTMLBrowser extends Browser implements CommProcessNotifier {

	private static final class Page {
		private Vector elements;
		/* Page title */
		private String title;
		/* The URL of this page */
		private String url;

		private Page() {
			elements = new Vector();
			title = "Aphrodite HTML Browser";
		}
	}

	private static final int brTagSpace = 2;

	static String currentUrl;

	static Font font = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_PLAIN, Font.SIZE_SMALL);
	static Font currentFont = font;

	private Page currentPage;

	private int currentX;
	private int currentY;

	private boolean isParsing;
	private String prevUrl = "";
	// private boolean showTitle = true;
	// private int titleColor = 0xffffff;

	// private int titleEndClr = 0x303030;

	// private int titleHeight;

	// private int titleStartClr = 0xA0A0A0;
	private int totalHeight = 2;

	public HTMLBrowser(Theme theme, int width, int height) {
		super(theme, width, height);
		currentPage = new Page();
		setTitle("Aphrodite Browser");
	}

	private void addBrowserEntity(BrowserElement element, Vector parts) {
		element.x = currentX;
		element.y = currentY;
		currentX += element.width;
		currentX += 4;/* space between elements */
		parts.addElement(element);
		/* Add element height only if widget is drawn in the next line */
		if (element.x == 2)
			totalHeight += element.height;
	}

	private void carrigeReturn() {
		currentX = 2;
		currentY = totalHeight + brTagSpace;
		totalHeight += brTagSpace;
	}

	public void cleanUp() {
		currentPage.elements.removeAllElements();
		previous.removeAllElements();
		next.removeAllElements();
	}

	public void goBack() {
		if (!previous.isEmpty()) {
			if (!currentPage.elements.isEmpty()) {
				next.push(currentPage);
				currentPage = (Page) previous.pop();
				reDrawWidget();
			}
		}
	}

	public void goForward() {
		if (!next.isEmpty()) {
			if (!currentPage.elements.isEmpty()) {
				previous.push(currentPage);
				currentPage = (Page) next.pop();
				reDrawWidget();
			}
		}
	}

	public void gotoURL(String url) {
		if (!isParsing) {
			reset();
			currentUrl = url;
			isParsing = true;
			HttpCommManager comm = new HttpCommManager();
			comm.setProcessNotifier(this);
			comm.setURL(url, HttpConnection.GET);
			Thread th = new Thread(comm);
			th.start();

		}
	}

	public void handleError(int code, String error) {
		System.out.println("Error has occured " + error);
		Page current = new Page();
		current.title = (code != 0) ? Integer.toString(code) : "Error";
		current.url = "";/* or else i cannot compare it in sendCurentBack :D */
		current.elements.addElement(new Body(this.width, this.height));
		addBrowserEntity(new P(error), current.elements);
		sendCurrentBack(current);
		reDrawWidget();

	}

	public void handleResource(InputStream is, long length) {
		parseHtml(is, currentUrl);
		currentUrl = null;
	}

	// int prevX = 2;

	private void parseHtml(InputStream is, String currentUrl) {
		System.out.println("============================Processing Input HTML====================");
		// Reader reader = new InputStreamReader(is);
		final Page newPage = new Page();
		newPage.url = currentUrl;
		try {
			final XMLReader parser = new XMLReader(is);
			int tagType;
			String tagName = "";
			BrowserElement element = null;
			for (; isParsing;) {
				tagType = parser.next();
				switch (tagType) {
				case XMLReader.START_TAG:
					tagName = parser.getName();
					System.out.println("Current tag Name " + tagName);
					if (tagName.equalsIgnoreCase("title")) {
						newPage.title = parser.readText();
						System.out.println("Page title:  " + newPage.title);
						/* <body> */
					} else if (tagName.equalsIgnoreCase("body")) {
						element = new Body(width, height);
						element.process(parser);
						newPage.elements.addElement(element);
						element = null;
					} else if (tagName.equalsIgnoreCase("a")) {
						element = new A();
					} else if (tagName.equalsIgnoreCase("p")) {
						carrigeReturn();
						element = new P(parser.readText());
					}
					// else if (tagName.equalsIgnoreCase("ul")) {
					// System.out.println("UL tag found ");
					// element = new UL();
					// parser.skip();
					// pe = parser.read();
					//
					// tagName = pe.getTagName();
					// System.out.println("Tag name " + tagName);
					// try {
					// // while (tagName.equalsIgnoreCase("li")) {
					// for (int i = 0; i < 1; i++) {
					// System.out.println("current tag is LI");
					// // ((UL) element).add(parser.readText());
					// parser.skip();
					// pe = parser.read();
					// tagName = pe.getTagName();
					// System.out.println("Inner tag name " + tagName);
					// }
					// } catch (Exception e) {
					// System.out.println("Exception " + e + " " +
					// e.getClass());
					// }
					// }
					if (element != null) {
						element.process(parser);
						addBrowserEntity(element, newPage.elements);
						element = null;
					}
					break;
				case XMLReader.END_TAG:
					tagName = parser.getName();
					if (tagName.equalsIgnoreCase("html")) {
						System.out.println("</html> found finishing parser");
						isParsing = false;
					}
					break;
				}
			}
			System.out.println("============================Processing Complete====================");
			parser.close();
		} catch (IOException e) {
			System.out.println("============================Processing NOT Complete====================" + e);
		}
		sendCurrentBack(newPage);
		System.out.println("finished parsing. " + newPage.elements.size() + " element(s) found");
		reDrawWidget();
	}

	// if (tagName.equalsIgnoreCase("title") && showTitle) {
	// newPage.title = parser.getText();
	// /* <body> */
	// } else if (tagName.equalsIgnoreCase("body")) {
	// element = new Body(width, height);
	// element.process(parser, pe, attr);
	// newPage.elements.addElement(element);
	// // System.out.println("body element added");
	// element = null;
	// // String text = parser.readText();
	// // if (text != null) {
	// // System.out.println("Body text " + text);
	// // element = new P(text);
	// // element.x = currentX++;
	// // element.y = currentY++;
	// // }
	//
	// } else if (tagName.equalsIgnoreCase("a")) {
	// element = new A(parser.readText());
	// } else if (tagName.equalsIgnoreCase("p")) {
	// carrigeReturn();
	// element = new P(parser.readText());
	// } else if (tagName.equalsIgnoreCase("ul")) {
	// System.out.println("UL tag found ");
	// element = new UL();
	// parser.skip();
	// pe = parser.read();
	//
	// tagName = pe.getTagName();
	// System.out.println("Tag name " + tagName);
	// try {
	// // while (tagName.equalsIgnoreCase("li")) {
	// for (int i = 0; i < 1; i++) {
	// System.out.println("current tag is LI");
	// // ((UL) element).add(parser.readText());
	// parser.skip();
	// pe = parser.read();
	// tagName = pe.getTagName();
	// System.out.println("Inner tag name " + tagName);
	// }
	// } catch (Exception e) {
	// System.out.println("Exception " + e + " " + e.getClass());
	// }
	// }
	// if (element != null) {
	// element.process(parser, pe, attr);
	// addBrowserEntity(element, newPage.elements);
	// element = null;
	// }
	// break;
	// case Xml.END_TAG:
	// tagName = pe.getTagName();
	// if (tagName.equalsIgnoreCase("html")) {
	// System.out.println("HTml end tag found");
	// isParsing = false;
	// break;
	// } else if (tagName.equalsIgnoreCase("br") ||
	// tagName.equalsIgnoreCase("p")) {
	// carrigeReturn();
	// }
	// break;
	//
	// }
	// }
	// System.out.println(
	// "============================Processing Complete===================="
	// );
	// } catch (IOException e) {
	// System.out.println(
	// "============================Processing NOT Complete===================="
	// + e);
	// }
	// // this.currentElements = parts;
	// sendCurrentBack(newPage);
	// System.out.println("finished parsing. " + newPage.elements.size() +
	// " element(s) found");
	// reDrawWidget();
	// }

	// private void parseHtml(InputStream is, String currentUrl) {
	// System.out.println(
	// "============================Processing Input HTML====================");
	// Reader reader = new InputStreamReader(is);
	// Page newPage = new Page();
	// newPage.url = currentUrl;
	// try {
	// XmlParser parser = new XmlParser(reader);
	// ParseEvent pe = null;
	// String tagName = "";
	// BrowserElement element = null;
	// Attribute attr = null;
	// parser.skip();
	// for (; isParsing;) {
	// pe = parser.read();
	// switch (pe.getType()) {
	// case Xml.START_TAG:
	// tagName = pe.getTagName();
	// System.out.println("Current tag Name " + tagName);
	// if (tagName.equalsIgnoreCase("title") && showTitle) {
	// newPage.title = parser.readText();
	// /* <body> */
	// } else if (tagName.equalsIgnoreCase("body")) {
	// element = new Body(width, height);
	// element.process(parser, pe, attr);
	// newPage.elements.addElement(element);
	// // System.out.println("body element added");
	// element = null;
	// // String text = parser.readText();
	// // if (text != null) {
	// // System.out.println("Body text " + text);
	// // element = new P(text);
	// // element.x = currentX++;
	// // element.y = currentY++;
	// // }
	//
	// } else if (tagName.equalsIgnoreCase("a")) {
	// element = new A(parser.readText());
	// } else if (tagName.equalsIgnoreCase("p")) {
	// carrigeReturn();
	// element = new P(parser.readText());
	// } else if (tagName.equalsIgnoreCase("ul")) {
	// System.out.println("UL tag found ");
	// element = new UL();
	// parser.skip();
	// pe = parser.read();
	//
	// tagName = pe.getTagName();
	// System.out.println("Tag name " + tagName);
	// try {
	// // while (tagName.equalsIgnoreCase("li")) {
	// for (int i = 0; i < 1; i++) {
	// System.out.println("current tag is LI");
	// // ((UL) element).add(parser.readText());
	// parser.skip();
	// pe = parser.read();
	// tagName = pe.getTagName();
	// System.out.println("Inner tag name " + tagName);
	// }
	// } catch (Exception e) {
	// System.out.println("Exception " + e + " " + e.getClass());
	// }
	// }
	// if (element != null) {
	// element.process(parser, pe, attr);
	// addBrowserEntity(element, newPage.elements);
	// element = null;
	// }
	// break;
	// case Xml.END_TAG:
	// tagName = pe.getTagName();
	// if (tagName.equalsIgnoreCase("html")) {
	// System.out.println("HTml end tag found");
	// isParsing = false;
	// break;
	// } else if (tagName.equalsIgnoreCase("br") ||
	// tagName.equalsIgnoreCase("p")) {
	// carrigeReturn();
	// }
	// break;
	//
	// }
	// }
	// System.out.println(
	// "============================Processing Complete====================");
	// } catch (IOException e) {
	// System.out.println(
	// "============================Processing NOT Complete===================="
	// + e);
	// }
	// // this.currentElements = parts;
	// sendCurrentBack(newPage);
	// System.out.println("finished parsing. " + newPage.elements.size() +
	// " element(s) found");
	// reDrawWidget();
	// }

	public void processComplete(boolean success) {}

	public void refresh() {
		gotoURL(currentUrl);
	}

	/**
	 * Reload the current page
	 */
	public void reload() {
		if (currentPage.url != null)
			gotoURL(currentPage.url);
	}

	public void render(Graphics g) {
		if (isVisible) {
			capture(g, width, height, false);
			// drawBrowser contents
			if (!currentPage.elements.isEmpty()) {
				for (int i = 0; i < currentPage.elements.size(); i++) {
					((BrowserElement) currentPage.elements.elementAt(i)).draw(g);
				}
			}
			release(g, width, height, true);
		}
	}

	private void reset() {
		currentX = 2;
		currentY = 2;
		totalHeight = 2;
	}

	private void sendCurrentBack(Page present) {
		System.out.println("Sending current screen back");
		if (!currentPage.elements.isEmpty()) {
			/*
			 * Dont add to page history if there are not elements in the current
			 * page
			 */
			System.out.println("Current screen is not empty");

			if (!present.url.equals(prevUrl)) {
				/*
				 * Dont add to history if its just a page refresh or a reloading
				 * of the same page
				 */
				previous.push(currentPage);
			}
		}
		prevUrl = present.url;
		currentPage = present;
		reDrawWidget();

	}

	public void setPercent() {}

	protected boolean traverse(int dir, int viewportWidth, int viewportHeight, int[] visRect_inout) {
		return false;
	}

	protected void updateModel() {
	// TODO Auto-generated method stub

	}
}
